﻿// Turtle Graphics
//===============================================================================
// Copyright 2009 Jason Hogg.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.

using System;
using System.Collections.Generic;
using System.Text;

// TODO: We create some redundant xaml path statements that could be removed
namespace TurtleGraphics
{
    /// <summary>
    /// This class takes the parsed output and interprets it, converting
    /// graphical instructions into WPF. 
    /// </summary>
    public class TurtleGraphicsInterpreter
    {
        string pgm = string.Empty;
        int angle = 0;

        public int Angle
        {
            get { return angle; }
            set { angle = value; }
        }
        int x = 200;

        public int X
        {
            get { return x; }
            set { x = value; }
        }
        int y = 200;

        public int Y
        {
            get { return y; }
            set { y = value; }
        }
        int oldX = 200;
        int oldY = 200;
        string color = "Blue";
        StringBuilder xamlOutput = new StringBuilder();

        // Xaml XML strings
        const string xamlGridInit = @" <Grid
                                        xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" 
                                        xmlns:sys=""clr-namespace:System;assembly=mscorlib"" 
                                        xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"" 
                                        Height=""568"" Width=""542"" 
                                        >";
        const string xamlGridClose = "</Grid>";
        const string xamlPathClose = @"  ""	/>";

        private TurtleGraphicsInterpreter() { }

        public TurtleGraphicsInterpreter(string pgm)
        {
            this.pgm = pgm;
            xamlOutput.Append(xamlGridInit);
        }

        // Interprets the program providing XAML output 
        public string Interpret()
        {

            string s2 = pgm;
            string[] stringSeparators = new string[] { " " };
            string[] result;
            result = s2.Split(stringSeparators, StringSplitOptions.None);

            double l = 0;
            string instruction;

            for (int loop = 0; loop < result.Length ; loop++)
            {
                // Initialize the next path statement including moving the cursor appropriately

                xamlOutput.Append(CreateXamlPathInit(color));
                xamlOutput.Append("M " + x.ToString() + " " + y.ToString() + " ");
                
                instruction = (string)result[loop];

                switch (instruction)
                {
                    case ("Color"):                        
                        color = result[loop + 1];
                        loop++;
                        break;

                    // Calculate the new endpoint - who said you would never use trig after school!
                    case ("Draw"):
                        l = Convert.ToDouble(result[loop + 1]);
                        x = Convert.ToInt32(x + (l * Math.Sin(ConvertDegreesToRadians(angle)))); // SOH-CAH-TOA
                        y = Convert.ToInt32(y + (l * Math.Cos(ConvertDegreesToRadians(angle))));
                        xamlOutput.Append("L " + x.ToString() + " " + y.ToString() + " " + Environment.NewLine);
                        loop++;
                        oldX = x;
                        oldY = y;
                        break;

                    // Rotate by the number of degrees specified 
                    case ("Rotate"):
                        angle -= Convert.ToInt32(result[loop + 1]);
                        loop++;
                        break;

                    // Move the cursor somewhere else on the screen
                    case ("MoveTo"):
                        x = Convert.ToInt32(result[loop + 1]);
                        y = Convert.ToInt32(result[loop + 2]);
                        xamlOutput.Append("M " + x.ToString() + "," + y.ToString() + " " + Environment.NewLine);
                        loop += 2;
                        oldX = x;
                        oldY = y;
                        break;

                    // Move the cursor somewhere else on the screen
                    case ("Move"):
                        x = oldX + Convert.ToInt32(result[loop + 1]);
                        y = oldY + Convert.ToInt32(result[loop + 2]);
                        xamlOutput.Append("M " + x.ToString() + "," + y.ToString() + " " + Environment.NewLine);
                        loop += 2;
                        oldX = x;
                        oldY = y;
                        break;
                    case ("Call"):
                        Console.WriteLine("In call function");
                        break;
                    default:
                        break;
                }
                xamlOutput.Append(xamlPathClose);            
            }
            xamlOutput.Append(xamlGridClose);
            return xamlOutput.ToString() ;            
        }

        private string CreateXamlPathInit(string color)
        {
            return @"<Path Stroke=""" + color + @""" StrokeThickness=""2""	StrokeLineJoin=""Round"" Data="" ";
        }

        // Sin and Cos functions work in Radians
        private Double ConvertDegreesToRadians(Double degrees)
        {
            return degrees * (Math.PI / 180);
        }
    }

}
